require("GtkCodeUtility")
require("GenCodeCommon")
require("GenGtkFormatWidgets")

local function build_widget_constructor_env(widget, root_node, parent)
	local env = {};
	-- widget指向控件
	env["widget"] = widget;
	-- 属性字段
	if widget["property"] ~= nil then
		-- this指向属性
		env["this"] = widget["property"];
		-- id字段
		if widget["property"]["id"] ~= nil then
			env["id"] = widget["property"]["id"].value;
		end
		-- class字段
		if widget["property"]["class"] ~= nil then
			env["class"] = widget["property"]["class"].value;
		end
	end
	env["parent"] = parent;
	env["root"] = root_node;
	return env;
end

local function build_widget_property_env(property, widget, root_node, parent)
	local env = {};
	-- widget指向控件
	env["widget"] = widget;
	-- 属性字段指向属性内容表
	env["property"] = property;
	-- 属性字段
	if widget["property"] ~= nil then
		-- this指向属性
		env["this"] = widget["property"];
		-- id字段
		if widget["property"]["id"] ~= nil then
			env["id"] = widget["property"]["id"].value;
		end
		-- class字段
		if widget["property"]["class"] ~= nil then
			env["class"] = widget["property"]["class"].value;
		end
	end
	env["parent"] = parent;
	env["root"] = root_node;
	return env;
end

local function build_widget_packing_property_env(packing, widget, root_node, parent)
	local env = {};
	-- parent指向父控件
	env["parent"] = parent;
	env["widget"] = widget;
	env["root"] = root_node;
	-- child 指向子控件
	if widget["property"] ~= nil then
		env["child"] = widget["property"];
	end
	-- packing指向packing属性
	env["packing"] = packing;
	-- 属性字段
	if parent["property"] ~= nil then
		-- id字段
		if parent["property"]["id"] ~= nil then
			env["id"] = parent["property"]["id"].value;
		end
		-- class字段
		if parent["property"]["class"] ~= nil then
			env["class"] = parent["property"]["class"].value;
		end
	end
	return env;
end

-- 判断当前节点是否有子控件
function Gtkui.HasChildWidget(this)
	return this.child ~= nil and this.child.widget;
end

-- 返回当前控件的子控件
function Gtkui.GetChildWidgets(this)
	return this.child.widget;
end

-- 根据名字获取控件表
function Gtkui.GetGtkClass(class_name)
	-- 判断相应的函数是否存在
	return GtkUtils.get_symbol_by_name(class_name, Gtk);
end

-- 根据名字获取控件的构造函数
function Gtkui.GetWidgetClass(widget)
	-- 判断相应的函数是否存在
	return Gtkui.GetGtkClass(widget.property.class.value);
end

-- 返回当前控件的构造函数
function Gtkui.GetWidgetCtor(widget, parent, root_node)
	-- 错误情况下，返回一个默认的构造函数
	local function get_bad_constructor(widget_name)
		return {name = "", params_type = {}, params_name = {}};
	end
	-- 获取控件的构造函数名称列表：以降序排列（参数个数）
	local function get_ctor_names_by_desc(widget_constructor)
		-- 构造函数名称列表：以降序排列（参数个数）
		local ctor_name_idx = {}

		-- 首先扫描当前widget的属性列表，找出参数最多的构造函数
		local ctor_param_max_count = 0;
		for name, ctor_info in pairs(widget_constructor) do
			-- 如果名字以__开头，且以__结尾，跳过此项
			if (not GtkUtils.str_starts(name, "__")) or (not GtkUtils.str_ends(name, "__")) then
				-- 判断长度
				if GtkUtils.table_length(ctor_info["params"]["name"]) > ctor_param_max_count then
					ctor_param_max_count = GtkUtils.table_length(ctor_info["params"]["name"]);
				end
			end
		end

		-- 然后以双层循环，找出参数个数等于ctor_param_max_count的构造函数
		local ctor_count = 0;
		-- 倒序遍历，从ctor_param_max_count开始，到0结束，每次递减1
		for ctor_param_count = ctor_param_max_count, 0, -1 do
			for name, ctor_info in pairs(widget_constructor) do
				-- 如果名字以__开头，且以__结尾，跳过此项
				if (not GtkUtils.str_starts(name, "__")) or (not GtkUtils.str_ends(name, "__")) then
					-- 每次插入参数个数等于ctor_param_count的构造函数
					if GtkUtils.table_length(ctor_info["params"]["name"]) == ctor_param_count then
						table.insert(ctor_name_idx, name);
						ctor_count = ctor_count + 1;
					end
				end
			end
		end
		return ctor_name_idx, ctor_count;
	end

	-- 取得控件类名
	local widget_name = widget.property.class.value
	-- 判断相应的函数是否存在
	local widget_class = Gtkui.GetWidgetClass(widget);
	-- 判断对应变量是否存在
	if widget_class == nil then
		print("[ERROR] missing class data, widget name : " .. widget_name)
		return get_bad_constructor(widget_name);
	end
	-- 判断构造函数是否存在
	if widget_class["constructor"] == nil then
		print("[ERROR] missing constructor inst in class data, widget name : " .. widget_name)
		return get_bad_constructor(widget_name);
	end
	-- 判断new 函数是否存在
	local widget_constructor = widget_class["constructor"];

	-- 根据当前组件的属性列表，来选择构建函数
	local ctor_name_idx, ctor_count = get_ctor_names_by_desc(widget_constructor);
	if ctor_count == 0 then
		print("[ERROR] missing constructor inst in class data, widget name : " .. widget_name)
		return get_bad_constructor(widget_name);
	end

	-- 如果只有一个，直接返回
	if ctor_count == 1 then
		return widget_constructor[ctor_name_idx[1]];
	end

	-- 控件的构造函数列表中，自带排序结果，则直接使用
	if widget_constructor["__sort__"] ~= nil then
		ctor_name_idx = widget_constructor["__sort__"];
	end

	-- 如果有多个，则根据属性列表，选择一个合适的构造函数
	for ctor_idx = 1, ctor_count do
		-- 获取构造函数名称
		local ctor_name = ctor_name_idx[ctor_idx];
		-- 获取构造函数信息
		local ctor_info = widget_constructor[ctor_name];
		-- 判断此构建函数所需要的属性是否都存在
		if GtkUtils.items_is_in_table(ctor_info["params"]["name"], widget["property"]) then
			return ctor_info;
		end
	end

	-- 都没有找到时，返回最后一个构造函数
	return widget_constructor[ctor_name_idx[ctor_count]];
end

-- 获取指定属性的默认值
function Gtkui.GetWidgetDefaultValue(widget, property_name)
	local function recursion_get_property_def_value(widget_class, property_name)
		-- 扫描当前widget的属性列表
		for name, value in pairs(widget_class["property"]) do
			if name == property_name then
				if value["__default__"] ~= nil then
					return value["__default__"]
				else
					print("[ERROR]GetWidgetDefaultValue, widget : ".. widget_class.class .." property " .. property_name ..  " has no default value");
					return "";
				end
			end
		end
		-- 如果存在implement，则还需要往每个implement的属性中查找一下
		if widget_class["implement"] ~= nil then
			for _, implement in ipairs(widget_class["implement"]) do
				if implement["property"] ~= nil then
					-- 判断property是否存在
					local widget_property = implement["property"];
					-- 判断property中是否存在
					if widget_property[property_name] ~= nil then
						-- 有默认值时返回默认值，否则跳出循环
						if widget_property[property_name]["__default__"] ~= nil then
							return widget_property[property_name]["__default__"]
						else
							print("[ERROR]GetWidgetDefaultValue, widget : ".. widget_class.class .." property " .. property_name ..  " has no default value");
							return "";
						end
					end
				end
			end
		end
		-- property不存在，且parent不为空，递归搜索
		if widget_class["parent"] ~= nil then
			return recursion_get_property_def_value(widget_class["parent"], property_name);
		end
		return ""
	end
	
	local widget_class = Gtkui.GetWidgetClass(widget)
	return recursion_get_property_def_value(widget_class, property_name);
end

-- 生成当前控件的构造函数
function Gtkui.GenWidgetCtorCode(ctor_build, widget, parent, root_node)
	-- 首先取得widget的构造函数
	if ctor_build == nil then
		print("[ERROR]GenWidgetCtorCode: widget: ".. widget.property.class.value .." has no constructor");
		return "";
	end
	if ctor_build["params"] == nil then
		print("[ERROR]GenWidgetCtorCode: widget: ".. widget.property.class.value .." has no constructor params");
		return "";
	end

	-- 判断构造函数所需参数是否全部存在
	local ctor_params = ctor_build["params"]["name"]
	-- 如果构造函数所需参数不存在，则使用控件的默认值
	for _, param_name in ipairs(ctor_params) do
		-- 判断当前控件实例中是否具有该属性的内容
		if widget["property"][param_name] == nil then
			-- 没有，则使用Gtk的默认值
			widget["property"][param_name] = {}
			widget["property"][param_name]["name"] = param_name
			widget["property"][param_name]["value"] = Gtkui.GetWidgetDefaultValue(widget, param_name)
		end
	end

	-- 构造环境
	local env = build_widget_constructor_env(widget, root_node, parent);
	print("[DEBUG] Start GenConstrutorCode: widget: ".. widget.property.class.value .. ", id: " .. widget.property.id.value);
	-- 编译模板并执行之
	local result = Gtkui.RenderTmplCode(ctor_build["gencode"], env);
	-- 返回结果
	return result;
end

-- 生成当前控件的构造函数
function Gtkui.RemoveWidgetCtorProperty(ctor_build, widget, parent, root_node)
	-- 首先取得widget的构造函数
	if ctor_build == nil then
		print("[ERROR]GenConstrutorCode: widget: ".. widget.property.class.value .." has no constructor");
		return "";
	end
	if ctor_build["params"] == nil then
		print("[ERROR]GenConstrutorCode: widget: ".. widget.property.class.value .." has no constructor params");
		return "";
	end

	-- 判断构造函数所需参数是否全部存在
	local ctor_params = ctor_build["params"]["name"]
	-- 如果构造函数所需参数不存在，则使用控件的默认值
	for _, param_name in ipairs(ctor_params) do
		-- 如果当前控件实例中具有该属性的内容，则删除之
		widget["property"][param_name] = nil
	end
end

-- 获取Gtk内置的信号处理函数列表
function Gtkui.GetGtkBuildinSignalHandler()
	return { gtk_widget_show = true,  gtk_widget_hide = true, gtk_widget_grab_focs = true, 
			 gtk_widget_destory = true, gtk_true = true, gtk_false = true, gtk_main_quit = true };
end

-- 错误情况下，返回一个默认的属性构造函数
local function get_bad_property(widget_name)
	return {__type__="void", __gencode__ = {""}, __is_bad__ = true};
end

-- 返回当前控件的属性构造代码
function Gtkui.GetWidgetNormalProperty(property, widget, parent, root_node)
	local function recursion_find_property_name(widget_class, property_name)
		-- 判断对应变量是否存在
		if widget_class == nil then
			print("[ERROR] missing class data!")
			return get_bad_property(property_name);
		end
		-- 判断属性字段是否存在
		if widget_class["property"] ~= nil then
			-- 判断property是否存在
			local widget_property = widget_class["property"];
			-- 判断property中是否存在
			if widget_property[property_name] ~= nil then
				return widget_property[property_name];
			end
			-- 判断property不存在
			--print("[INFO] missing property data in class data, class: " .. widget_class["class"] .. ", property name: " .. property_name)
		else
			--print("[INFO] missing property inst in class data, class: " .. widget_class["class"] .. ", property name: " .. property_name)
		end
		-- 如果存在implement，则还需要往每个implement的属性中查找一下
		if widget_class["implement"] ~= nil then
			for _, implement in ipairs(widget_class["implement"]) do
				if implement["property"] ~= nil then
					-- 判断property是否存在
					local widget_property = implement["property"];
					-- 判断property中是否存在
					if widget_property[property_name] ~= nil then
						return widget_property[property_name];
					end
				end
			end
		end
		-- property不存在，且parent不为空，递归搜索
		if widget_class["parent"] ~= nil then
			return recursion_find_property_name(widget_class.parent, property_name);
		end
		-- 失败时，返回一个默认错误的属性构造体
		return get_bad_property(property_name)
	end
	
	-- 获取控件名称
	local widget_name = widget.property.class.value
	-- 判断相应的函数是否存在
	local widget_class = Gtkui.GetWidgetClass(widget);
	-- 判断对应变量是否存在
	if widget_class == nil then
		print("[ERROR] missing class data, widget name : " .. widget_name)
		return get_bad_property(widget_name);
	end
	-- 判断对应属性在当前类中是否存在
	return recursion_find_property_name(widget_class, property.name);
end

-- 返回当前控件的属性构造代码，支持正常与正则表达式匹配
function Gtkui.GetWidgetProperty(property, widget, parent, root_node)
	-- 首先取得property的信息结构表普通信息表
	local property_build = Gtkui.GetWidgetNormalProperty(property, widget, parent, root_node)
	-- 如果匹配错误，则再尝试一次正则匹配
	if property_build["__is_bad__"] == true then
		return Gtkui.GetWidgetRegexProperty(property, widget, parent, root_node)
	end
	return property_build;
end

-- 返回当前控件的属性构造代码
function Gtkui.GetPackingPropertyCode(packing, widget, parent, root_node)
	-- 错误情况下，返回一个默认的属性构造函数
	local function get_bad_packing_code(widget_name)
		return {name={}, gencode = "", __is_bad__ = true, can_skip = true};
	end

	-- 返回packing格式的名称列表
	local function get_packing_names(packing)
		local packing_name = {}
		for key, item in pairs(packing) do
			if item.name == nil then
				print("[ERROR] bad packing data, missing packing name.")
			elseif key ~= item.name then
				print("[ERROR] bad packing data, packing name not equal key, key: " .. key .. " name: " .. item.name)			
			else
				table.insert(packing_name, item.name)
			end
		end
		return packing_name
	end

	local function recursion_fill_packing_gencode(packing_build, packing_names, widget_class, root_name)
		-- 判断对应变量是否存在
		if widget_class == nil then
			print("[ERROR] missing class data!")
			return packing_build;
		end
		-- 判断packing是否存在
		if widget_class["packing"] ~= nil and GtkUtils.table_length(widget_class["packing"]) > 0 then
			-- 根据packing的属性，顺序搜索到匹配项
			for _, packing_build_ in ipairs(widget_class["packing"]) do
				-- 如果group以or算法进行检查，则packing_names中只需要有一项在packing_build_["group"]中
				if (packing_build_["group_or_check"] and GtkUtils.one_item_of_table_is_in_table2(packing_names, packing_build_["group"])) or 
					-- packing_names的名字集，当前packing子项中，如果
					GtkUtils.table_has_same_values(packing_build_["group"], packing_names) then
					-- return packing_build_["group_code"];
					for _, group_code_item in ipairs(packing_build_["group_code"]) do
						-- 不管什么情况，当前的group_code是可以添加到末尾的
						table.insert(packing_build, group_code_item)
						-- 添加一项后，packing_names相应根据调整
						packing_names = GtkUtils.intersect(packing_names, group_code_item.name)
						-- 如果还有一个filter_out字段，也需要过滤一下
						if (group_code_item.filter_out ~= nil) then
							packing_names = GtkUtils.intersect(packing_names, group_code_item.filter_out)
						end
						-- 如果packing_names已经处理完了，则可以直接返回了
						if #packing_names == 0 and #packing_build > 0 then
							return packing_build;
						end
					end
				end
			end
		end
		-- 如果packing_names已经处理完了，则可以直接返回了
		if #packing_names == 0 then
			-- 已经有匹配项，则可以直接返回了
			if #packing_build > 0 then
				return packing_build;
			end
		end
		-- property不存在，且parent不为空，递归搜索
		if widget_class["parent"] ~= nil then
			return recursion_fill_packing_gencode(packing_build, packing_names, widget_class["parent"], root_name);
		end
		-- 如果packing_names未处理
		if #packing_names > 0 then
			print("[WARN] mismatch packing_names, widget: [" .. root_name ..  "], packing: [" .. table.concat(packing_names, ",") .. "]");
		end
		return packing_build
	end

	print("[DEBUG] Start GetPackingPropertyCode, widget: [" .. widget.property.class.value ..  "], id: [" .. widget.property.id.value .. "]");
	-- 获取控件名称
	local widget_name = parent.property.class.value
	-- 判断相应的函数是否存在
	local widget_class = Gtkui.GetWidgetClass(parent);
	-- 判断对应变量是否存在
	if widget_class == nil then
		print("[ERROR] missing class data, widget name : " .. widget_name)
		return get_bad_packing_code(widget_name);
	end
	-- 根据packing取得packing_names
	local packing_names = get_packing_names(packing)

	local packing_build = {}
	-- 递归去整合父子关联代码生成器
	recursion_fill_packing_gencode(packing_build, packing_names, widget_class, widget_name);
	-- 如果没有找到合适的，则返回错误的
	if #packing_build == 0 then
		print("[ERROR] mismatch packing build data, widget name: " .. widget_name)
		return get_bad_packing_code(widget_name);
	end
	-- 返回
	return packing_build;
end

-- 获取控件的类名
function Gtkui.GetClassName(widget)
	-- 暂时只需要返回控件的类名
	local class_name = widget.property.class.value;
	-- 如果是模板类，则返回父类名
	if widget.property.__parent_class__ ~= nil then
		return widget.property.__parent_class__.value;
	end
	return class_name;
end

-- 是否需要隐藏的属性
function Gtkui.IsHidePropertyCode(property, widget, parent, root_node)
	if property.name == "id" or property.name == "class" then
		return true;
	end
	--[[
	-- 取得build
	local prop_build = Gtkui.GetWidgetNormalProperty(property, widget, parent, root_node)
	-- 只读的属性，不需要生成代码
	if prop_build["rwflags"] == "r" then
		print("[INFO] readonly property, skip code build property name : " .. property.name .. " in " .. widget.property.class.value)
		return true;
	end
	]]--
	return false;
end

-- 返回当前控件的属性构造代码：根据正则表达式来匹配
function Gtkui.GetWidgetRegexProperty(property, widget, parent, root_node)
	local function recursion_find_regex_property_name(widget_class, property_name)
		-- 判断对应变量是否存在
		if widget_class == nil then
			print("[ERROR] missing class data!")
			return get_bad_property(property_name);
		end
		-- 判断构造函数是否存在
		if widget_class["property"] ~= nil then
			-- 判断property是否存在
			local widget_property = widget_class["property"];
			-- 循环判断一下
			for key_, item in pairs(widget_property) do
				-- 仅处理支持正则表达式的属性项
				if item["regex"] ~= nil and item["regex"] then
					if string.match(property_name, key_) then
						return item;
					end
				end
			end
			-- 判断property不存在
			--print("[INFO] missing property data in class data, class: " .. widget_class["class"] .. ", property name: " .. property_name)
		else
			--print("[INFO] missing property inst in class data, class: " .. widget_class["class"] .. ", property name: " .. property_name)
		end
		-- property不存在，且parent不为空，递归搜索
		if widget_class["parent"] ~= nil then
			return recursion_find_regex_property_name(widget_class["parent"], property_name);
		end
		-- 失败时，返回一个默认错误的属性构造体
		return get_bad_property(property_name)
	end

	-- 获取控件名称
	local widget_name = widget.property.class.value
	-- 判断相应的函数是否存在
	local widget_class = Gtkui.GetWidgetClass(widget);
	-- 判断对应变量是否存在
	if widget_class == nil then
		print("[ERROR] missing class data, widget name : " .. widget_name)
		return get_bad_property(widget_name);
	end
	-- 判断对应属性在当前类中是否存在
	return recursion_find_regex_property_name(widget_class, property.name);
end

-- 生成当前控件的属性代码
function Gtkui.GetPropertyCodeList(property, widget, parent, root_node)
	print("[DEBUG] Start GetPropertyCodeList: property, name: [" .. property.name .. "], value: [" .. property.value .. "], widget: [" .. widget.property.class.value .. "]");
	-- 首先取得property的信息结构表
	local property_build = Gtkui.GetWidgetProperty(property, widget, parent, root_node)
	-- 如果某个属性没有
	if property_build["__gencode__"] == nil then
		print("[ERROR] missing gencode in property, name: [" .. property.name .. "], value: [" .. property.value .. "], widget: [" .. widget.property.class.value .. "]")
		return {"[ERROR] missing gencode in property, name: " .. property.name .. ", value: " .. property.value};
	end

	-- 如果当前属性的代码生成需要更多属性
	if property_build["__need_more__"] ~= nil then
		-- 遍历确保所有属性都得有
		for _, property_item in ipairs(property_build["__need_more__"]) do
			if widget.property[property_item] == nil then
				-- 没有，则使用Gtk的默认值
				widget.property[property_item] = {}
				widget.property[property_item]["name"] = property_item
				widget.property[property_item]["value"] = Gtkui.GetWidgetDefaultValue(widget, property_item)
			end
		end
	end

	-- 遍历所有代码行
	local result = {}
	-- 构造环境
	local env = build_widget_property_env(property, widget, root_node, parent);
	for _, a_tmpl_code in ipairs(property_build["__gencode__"]) do
		-- 编译模板并执行之
		local one_line = Gtkui.RenderTmplCode(a_tmpl_code, env);
		-- 如果解析失败，则报错，否则添加到结果列表中
		if one_line == nil then
			print("[ERROR] bad code in property, name: [" .. property.name .. "], value: [" .. property.value .. "], widget: [" .. widget.property.class.value .. "], tmpl code: " .. a_tmpl_code)
			return {"[ERROR] bad code in property, name: " .. property.name .. ", value: " .. property.value .. ", tmpl code: " .. a_tmpl_code};
		else
			table.insert(result, one_line)
		end
	end
	-- 执行结果
	return result;
end

-- 错误情况下，返回一个默认的属性构造函数
local function get_bad_group_property(widget_name)
	return {{name={}, gencode = "", __is_bad__ = true}};
end

-- 返回当前控件的属性构造代码
local function get_widget_group_property(property, widget, parent, root_node)
	-- 递归搜索group属性
	local function recursion_find_group_property_name(widget_class, property_name)
		-- 判断对应变量是否存在
		if widget_class == nil then
			print("[ERROR] missing class data!")
			return get_bad_group_property(property_name);
		end
		-- 判断构造函数是否存在
		if widget_class["property"] ~= nil then
			-- 判断property是否存在
			local widget_property = widget_class["property"];
			-- 当前类中，是否有group属性
			if widget_property["__group__"] ~= nil then
				local tmp_prop_tbl = {property_name}
				-- 遍历判断
				for _, group_prop in ipairs(widget_property["__group__"]) do
					-- 判断是否匹配
					if group_prop["group"] ~= nil and GtkUtils.table_has_same_values(tmp_prop_tbl, group_prop["group"]) then
						return group_prop["group_code"];
					end
				end
			end
			-- 判断property不存在
			--print("[INFO] missing property data in class data, class: " .. widget_class["class"] .. ", property name: " .. property_name)
		else
			--print("[INFO] missing property inst in class data, class: " .. widget_class["class"] .. ", property name: " .. property_name)
		end
		-- property不存在，且parent不为空，递归搜索
		if widget_class["parent"] ~= nil then
			return recursion_find_group_property_name(widget_class["parent"], property_name);
		end
		-- 失败时，返回一个默认错误的属性构造体
		return get_bad_group_property(property_name)
	end
	
	-- 获取控件名称
	local widget_name = widget.property.class.value
	-- 判断相应的函数是否存在
	local widget_class = Gtkui.GetWidgetClass(widget);
	-- 判断对应变量是否存在
	if widget_class == nil then
		print("[ERROR] missing class data, widget name : " .. widget_name)
		return get_bad_group_property(widget_name);
	end
	-- 判断对应属性在当前类中是否存在
	return recursion_find_group_property_name(widget_class, property.name);
end

-- 生成当前控件的属性代码
function Gtkui.GetGroupPropertyBuild(property, widget, parent, root_node)
	print("[DEBUG] Start GenGroupPropertyCode: property, name: [" .. property.name .. "], value: [" .. property.value .. "], widget: [" .. widget.property.class.value .. "]");
	-- 首先取得property的信息结构表
	local group_prop_builds = get_widget_group_property(property, widget, parent, root_node)
	-- 至少应该有一个，且其中应该有gen_code字段
	if group_prop_builds == nil or group_prop_builds[1]["gen_code"] == nil then
		print("[ERROR] missing gencode in group property, name: [" .. property.name .. "], value: [" .. property.value .. "], widget: [" .. widget.property.class.value .. "]")
		return get_bad_group_property(widget);
	end

	-- 如果只有一个，直接返回
	if #group_prop_builds == 1 then
		return group_prop_builds[1];
	end

	-- 如果有多个，则根据属性列表，选择一个合适的构造函数
	for bld_idx = 1, #group_prop_builds do
		-- 判断此构建函数所需要的属性是否都存在
		if GtkUtils.items_is_in_table(group_prop_builds[bld_idx]["name"], widget["property"]) then
			return group_prop_builds[bld_idx];
		end
	end

	-- 如果没有找到合适的，则返回第一个
	return group_prop_builds[1];
end

-- 生成当前控件的属性代码
function Gtkui.GenGroupPropertyCode(group_prop_build, property, widget, parent, root_node)
	-- 至少应该有一个，且其中应该有gen_code字段
	if group_prop_build == nil or group_prop_build["gen_code"] == nil then
		return "[ERROR] missing gencode in group property, name: " .. property.name .. ", value: " .. property.value;
	end

	-- 如果packing函数所需参数不存在，则使用控件的默认值
	for _, param_name in ipairs(group_prop_build["name"]) do
		-- 判断当前控件实例中是否具有该属性的内容
		if widget.property[param_name] == nil then
			-- 没有，则使用Gtk的默认值
			widget.property[param_name] = {}
			widget.property[param_name]["name"] = param_name
			widget.property[param_name]["value"] = Gtkui.GetWidgetDefaultValue(widget, param_name)
		end
	end

	-- 构造环境
	local env = build_widget_property_env(property, widget, root_node, parent);
	-- 编译模板并执行之
	local result = Gtkui.RenderTmplCode(group_prop_build["gen_code"], env);
	-- 执行结果
	return result;
end

function Gtkui.IsGroupProperty(property, widget, parent, root_node)
	-- 获取其组属性构造体
	local group_prop_builds = get_widget_group_property(property, widget, parent, root_node)
	-- 获取到了，则认为是组属性
	if group_prop_builds ~= nil and group_prop_builds[1] ~= nil and (not group_prop_builds[1].__is_bad__) then
		return true;
	end
	return false;
end

-- 是否需要隐藏的属性
function Gtkui.HasGroupProperty(propertys, widget, parent, root_node)
	-- 循环判断即可
	for _, property in pairs(propertys) do
		if Gtkui.IsGroupProperty(property, widget, parent, root_node) then
			return true;
		end
	end
	return false;
end

-- 删除已经处理过的组属性
function Gtkui.RemoveWidgetGroupProperty(group_prop_build, widget, parent, root_node)
	local prop_names = group_prop_build["name"];
	-- 删除其中的属性
	for name_idx = 1, #prop_names do
		widget.property[prop_names[name_idx]] = nil;
	end
end

-- 生成当前控件的Packing属性代码，通常就是子组件添加至父组件中
function Gtkui.HasPackingPropertyCode(child_idx, widget, parent, root_node)
	-- 校验一下，防止误用
	if child_idx ~= nil and parent ~= nil and parent.child ~= nil and 
		parent.child.packing ~= nil and parent.child.packing[child_idx] ~= nil then
		return true;
	end
	if child_idx ~=nil and parent ~= nil then
		print("[DEBUG] Skip GenPackingPropertyCode, idx: " .. child_idx .. ", widget: ".. widget.property.class.value .. " parent: ".. parent.property.class.value);
	elseif child_idx ~=nil then
		print("[DEBUG] Skip GenPackingPropertyCode, idx: " .. child_idx .. ", widget: ".. widget.property.class.value);
	else
		print("[DEBUG] Skip GenPackingPropertyCode, widget: ".. widget.property.class.value);
	end
	return false;
end

-- 获取指定属性的默认值
function Gtkui.GetPackingProperty(parent, property_name)
	local function recursion_get_packing_value(widget_class, property_name)
		-- 如果不为空，则检查一下
		if widget_class["child_property"] ~= nil then
			-- 扫描当前widget的child_property属性列表
			for name, value in pairs(widget_class["child_property"]) do
				-- 名字相同，则在有默认值时返回默认值
				if name == property_name then
					return value;
				end
			end
		end
		-- property不存在，且parent不为空，递归搜索
		if widget_class["parent"] ~= nil then
			return recursion_get_packing_value(widget_class["parent"], property_name);
		end
		print("[ERROR] can't found in child_property, name: " .. property_name .. ", widget: " .. widget_class.class)
		return {}
	end
	
	local widget_class = Gtkui.GetWidgetClass(parent)
	return recursion_get_packing_value(widget_class, property_name);
end

-- 获取指定属性的默认值
function Gtkui.GetPackingDefaultValue(parent, property_name)
	local packing_info = Gtkui.GetPackingProperty(parent, property_name);
	return packing_info["__default__"] or "";
end

function Gtkui.IsCanSkipPackingPropertyCode(packing_build, packing, widget, parent, root_node)
	-- 如果没有__gencode__则无法生成代码
	if packing_build["gen_code"] == nil then
		print("[ERROR] missing gencode in packing, [" .. table.concat(packing, ",") .. "], widget: [" .. widget.property.class.value .. "]")
		return true;
	end
	-- 如果build中标明，可以skip
	if packing_build["can_skip"] ~= nil then
		print("[WARN] Skip gencode in packing, [" .. table.concat(packing_build["name"], ",") .. "], widget: [" .. widget.property.class.value .. "]")
		return true;
	end

	-- 如果packing函数所需参数不存在，则使用控件的默认值
	for _, param_name in ipairs(packing_build["name"]) do
		-- 判断当前控件实例中是否具有该属性的内容
		if packing[param_name] == nil then
			-- 如果build中标明，可以skip
			if packing_build["can_skip"] ~= nil then
				print("[WARN] Skip gencode param_name: " .. param_name .. " is nil and packing_build set can_skip flags, widget: " .. widget.property.class.value)
				return true;
			end
		end
	end
	return false;
end

-- 生成当前控件的Packing属性代码，通常就是子组件添加至父组件中
function Gtkui.GenPackingPropertyCode(packing_build, packing, widget, parent, root_node)
	-- 如果没有__gencode__则无法生成代码
	if packing_build["gen_code"] == nil then
		print("[ERROR] missing gencode in packing, [" .. packing .. "], widget: [" .. widget.property.class.value .. "]")
		return "[ERROR] missing gencode in packing, name: " .. packing;
	end

	-- 如果packing函数所需参数不存在，则使用控件的默认值
	for _, param_name in ipairs(packing_build["name"]) do
		-- 判断当前控件实例中是否具有该属性的内容
		if packing[param_name] == nil then
			-- 如果build中标明，可以skip
			if packing_build["can_skip"] ~= nil then
				print("[WARN] Skip gencode when param_name: " .. param_name .. " is nil and packing_build set can_skip flags, widget: " .. widget.property.class.value)
				return "";
			end

			-- 没有，则使用Gtk的默认值
			packing[param_name] = {}
			packing[param_name]["name"] = param_name
			packing[param_name]["value"] = Gtkui.GetPackingDefaultValue(parent, param_name)
		end
	end

	-- 构造环境
	local env = build_widget_packing_property_env(packing, widget, root_node, parent);
	print("[DEBUG] Start GenPackingPropertyCode, widget: ".. widget.property.class.value .. 
	                   " parent: ".. parent.property.class.value .. 
					   "[" .. table.concat(packing_build["name"], ",") .. "]");
	-- 编译模板并执行之
	local result = Gtkui.RenderTmplCode(packing_build.gen_code, env);
	-- 执行结果
	return result;
end

-- 返回当前控件件的所有子、孙控件
function Gtkui.GetTotalDescendantWidgets(child_widget, parent_widget, root_node, child_idx)
	local widget_data = {};
	-- 先插入当前实例
	table.insert(widget_data, {child_widget, parent_widget, child_idx});
	-- 如果有子控件，则递归处理
	if child_widget.child ~= nil and child_widget.child.widget ~= nil then
		for idx_2, child in pairs(child_widget.child.widget) do
			-- 递归获取子控件数据
			local child_data = Gtkui.GetTotalDescendantWidgets(child, child_widget, root_node, idx_2);
			-- 合并进当前结果
			GtkUtils.copy_to_left(widget_data, child_data);
		end
	end
	return widget_data;
end

-- 判断当前节点是否有信号
function Gtkui.HasSignal(child_widget, parent_widget, root_node)
	if child_widget.signal ~= nil then
		return true;
	end
	return false;
end

-- 获取当前节点的信号列表
function Gtkui.GetSignalCode(child_widget, parent_widget, root_node)
	-- 错误情况下，返回一个默认的属性构造函数
	local function get_bad_signal(widget_name)
		return {ret_type = "void", params = { type = {"void*"}, name = {"var"}}, __is_bad__ = true};
	end

	local function recursion_find_signal_name(widget_class, signal_name)
		-- 判断对应变量是否存在
		if widget_class == nil then
			print("[ERROR] missing class data!")
			return get_bad_signal(signal_name);
		end
		-- 判断信号是否存在
		if widget_class["signal"] ~= nil then
			-- 判断signal是否存在
			local widget_signal = widget_class["signal"];
			-- 判断signal中是否存在
			if widget_signal[signal_name] ~= nil then
				return widget_signal[signal_name];
			end
			-- 判断signal不存在
			--print("[INFO] missing signal data in class data, class: " .. widget_class["class"] .. ", signal name: " .. signal_name)
		else
			--print("[INFO] missing signal inst in class data, class: " .. widget_class["class"] .. ", signal name: " .. signal_name)
		end
		-- 如果存在implement，则还需要往每个implement的signal中查找一下
		if widget_class["implement"] ~= nil then
			for _, implement in ipairs(widget_class["implement"]) do
				if implement["signal"] ~= nil then
					-- 判断signal是否存在
					local widget_signal = implement["signal"];
					-- 判断signal中是否存在
					if widget_signal[signal_name] ~= nil then
						return widget_signal[signal_name];
					end
				end
			end
		end
		-- property不存在，且parent不为空，递归搜索
		if widget_class["parent"] ~= nil then
			return recursion_find_signal_name(widget_class["parent"], signal_name);
		end
		print("[ERROR] missing signal inst in class data, class: " .. widget_class["class"] .. ", signal name: " .. signal_name)
		-- 失败时，返回一个默认错误的信号构造体
		return get_bad_signal(signal_name)
	end
	-- 返回当前控件的属性构造代码
	local function get_signal_declare(signal, widget, parent, root_node)
		-- 获取控件名称
		local widget_name = widget.property.class.value
		-- 判断相应的函数是否存在
		local widget_class = Gtkui.GetWidgetClass(widget);
		-- 判断对应变量是否存在
		if widget_class == nil then
			print("[ERROR] missing class data, widget name : " .. widget_name)
			return get_bad_signal(widget_name);
		end
		-- 判断对应信号在当前类中是否存在
		return recursion_find_signal_name(widget_class, signal.name);
	end

	-- 如果没有信号，则返回空
	if child_widget.signal == nil then
		return {}
	end

	-- 信号的信息列表
	local signal_list = {};
	-- 遍历所有信号
	for _1, signal_ in pairs(child_widget.signal) do
		local signal_data = {};
		-- 信号名称
		signal_data["name"] = signal_.name;
		-- 信号处理函数
		signal_data["handler"] = signal_.handler;

		-- 从GTK20.lua中获取信号声明
		local widget_signal = get_signal_declare(signal_, child_widget, parent_widget, root_node);

		-- 信号处理函数的返回值类型
		signal_data["ret_type"] = widget_signal.ret_type;
		-- 信号处理函数的参数信息
		signal_data["params"] = widget_signal.params;
		-- 插入并返回信号处理函数的参数列表
		table.insert(signal_list, signal_data);
	end

	return signal_list;
end

-- 组件的依赖列表
Gtkui.widget_depends_list = {}

-- 组件的外部模块列表
Gtkui.ext_module_list = {}

-- 组件的外部头文件列表
Gtkui.ext_inc_file_list = {}

-- 组件的属性输出格式列表
Gtkui.property_patch_list = {
	-- 多行字符串
	["GStrv"] = function(property_, class_name)
		-- 处理每一行的信息，
		local m_lines = GtkUtils.string_split(property_.value, "\n")
		property_.value = '"' .. table.concat(m_lines, "\",\"") .. '"';
	end,
	-- 字符串，需要需要翻译，则加上_T()，否则加上引号即可
	["const gchar*"] = function(property_, class_name)
		if property_.translatable == "yes" then
			property_.value = '_T("' .. property_.value .. '")';
		else
			property_.value = '"' .. property_.value .. '"';
		end
	end,
	-- 字符串，需要需要翻译，则加上_T()，否则加上引号即可
	["gchar*"] = function(property_, class_name)
		if property_.translatable == "yes" then
			property_.value = '_T("' .. property_.value .. '")';
		else
			property_.value = '"' .. property_.value .. '"';
		end
	end,
	-- 字符数组，需要需要翻译，与字符串类似
	["gchararray"] = function(property_, class_name)
		if property_.translatable == "yes" then
			property_.value = '_T("' .. property_.value .. '")';
		else
			property_.value = '"' .. property_.value .. '"';
		end
	end,
	-- GdkPixbuf*，通常加载自文件，因此需要加上引号
	["GdkPixbuf*"] = function(property_, class_name)
		property_.value = "GET_GDK_PIX_BUF(\"" .. property_.value .. "\")";
	end,
	-- 布尔值，需要转换为大写
	["gunichar"] = function(property_, class_name)
		property_.value = "'" .. property_.value .. "'";
	end,
	-- 布尔值，需要转换为大写
	["gboolean"] = function(property_, class_name)
		property_.value = string.upper(property_.value);
	end,
	-- 颜色，需要调用额外函数来转换
	["GdkColor*"] = function(property_, class_name)
		property_.value = 'GET_GDK_COLOR("' .. property_.value .. '")';
	end,
	-- 颜色，需要调用额外函数来转换
	["GdkRGBA*"] = function(property_, class_name)
		property_.value = 'GET_GDK_RGBA("' .. property_.value .. '")';
	end,
};

function Gtkui.PatchOneProperyValueToCFormat(property_, prop_build, class_name)
	-- 如果包含is_top_widget，则需要替换为TOP_WIDGET
	if prop_build.is_top_widget ~= nil and prop_build.is_top_widget == true then
		-- 如果在主控件列表中，则包装为TOP_WIDGET()，否则包装成EXT_WIDGET()
		if Gtkui.has_main_widget == nil or Gtkui.has_main_widget == false then
			property_.value = 'EXT_WIDGET(' .. property_.value .. ')';
		else
			property_.value = 'TOP_WIDGET(' .. property_.value .. ')';
		end
		return;
	end
	-- 取得相应的类型
	local prop_type = prop_build["__type__"]
	-- 遍历查找到匹配的属性patch函数
	for name, property_patch in pairs(Gtkui.property_patch_list) do
		-- 根据类型的名字进行匹配
		if name == prop_type then
			-- 判断类型
			if type(property_patch) == "function" then
				-- 
				property_patch(property_, class_name)
				return;
			end
		end
	end
	-- 如果找不到，且能够在枚举中找到，则使用枚举的宏来替换
	if Gtk.GtkEnumerationes[prop_type] ~= nil then
		for _, enum_ in pairs(Gtk.GtkEnumerationes[prop_type]) do
			if enum_.name == property_.value then
				property_.value = enum_.macro;
				return;
			elseif enum_.nick == property_.value then
				property_.value = enum_.macro;
				return;
			end
		end
	end
end

-- 判断组件是否为模板控件
function Gtkui.IsTemplateWidget(widget)
	-- 判断属性中的类名及是否有__parent_class__ 属性
	if widget.property ~= nil and widget.property.__parent_class__ ~= nil then -- and widget.property.class.value == "GtkTmplWidget"
		return true
	end
	return false
end

-- 判断组件是否为模板控件
function Gtkui.IsTemplateWidgetByName(widget_name)
	if Gtkui.ProjectIdList == nil then
		return false
	end
	-- 根据ProjectIdList来判断
	for _, widget_ in pairs(Gtkui.ProjectIdList) do
		if widget_.class == widget_name and widget_.is_template then
			return true
		end
	end
	return false
end

-- 以顺序返回控件的依赖列表
function Gtkui.GetWidgetDependsList(widget, root_node)
    -- 递归修改控件的依赖值
    local function recursion_change_widget_dep_list(widget_name, root, depend_val_hash)
        -- 修改依赖控件的依赖值
        local new_val = depend_val_hash[widget_name] + 1
        local ret_val = new_val
		-- 如果控件不在顶层（模板控件，或跨文件控件），则修改一下此控件的依赖值，然后就可以返回了
		if root[widget_name] == nil then
            if depend_val_hash[widget_name] < new_val then
                depend_val_hash[widget_name] = new_val
            end
			return ret_val
		end
        -- 遍历所有依赖的控件
        for _, depend_widget in ipairs(root[widget_name]) do
            if depend_val_hash[depend_widget] < new_val then
                depend_val_hash[depend_widget] = new_val
            end
            -- 递归处理子控件，这里没考虑循环依赖的情况
            local new_ret = recursion_change_widget_dep_list(depend_widget, root, depend_val_hash)
            if new_ret > ret_val then
                ret_val = new_ret
            end
        end
        return ret_val
    end

	local result_hash = {}
	local result_list = {}
	-- 遍历每一个顶层控件，设置其依赖值为0
	for name, _ in pairs(root_node) do
		result_hash[name] = -1
	end
	-- 遍历控件依赖列表，如果不在结果列表中，则加入结果列表
	for widget_name, depend_list in pairs(Gtkui.widget_depends_list) do
		-- 将依赖列表中的控件加入结果列表
		for _, widget_item in ipairs(depend_list) do
			if result_hash[widget_item] == nil then
				result_hash[widget_item] = -1;
			end
		end
		-- 将控件本身加入结果列表
		if result_hash[widget_name] == nil then
			result_hash[widget_name] = -1;
		end
	end
	-- 如果没有指定控件，返回一个空列表
	if result_hash[widget] == nil then
		return {}
	end
	-- 有，则设置此控件的关联依赖值为1
	result_hash[widget] = 0

	-- 循环遍历处理，直到没有依赖的控件为止，同时会返回最大的依赖值
    local max_dep_val = recursion_change_widget_dep_list(widget, Gtkui.widget_depends_list, result_hash)

    -- 依次从Hash表中取出依赖值最大的控件
    for idx = max_dep_val, 0, -1 do
        -- 遍历每一个控件，
        for widget_name, depend_val in Gtkui.pairs(result_hash) do
            -- 如果依赖值等于当前值，则加入结果列表
            if depend_val == idx then
                table.insert(result_list, widget_name)
            end
        end
    end

	return result_list
end

-- 返回所有外部模块列表，不依赖于某个组件
function Gtkui.GetExtModuleList(root_node)
	local result_hash = {}
	local result_list = {}
	for _, child_list in pairs(Gtkui.ext_module_list) do
		if #child_list > 0 then
			for _, child_name in ipairs(child_list) do
				-- 如果不存在，则添加进去
				if result_hash[child_name] == nil then
					result_hash[child_name] = true
					table.insert(result_list, child_name)
				end
			end
		end
	end
	return result_list;
end

-- 返回控件的外部头文件列表
function Gtkui.GetExtIncFileList(widget, root_node)
	return Gtkui.ext_inc_file_list[widget];
end

-- 返回当前控件的属性所有前置声明
function Gtkui.GetMacroCodeNameList(widget_data, type_id)
    -- 递归修改控件的依赖值
    local function recursion_get_macro_code(widget_data, code_hash)
		-- 遍历所有属性
		for _, prop_info in pairs(widget_data.property) do
			-- 取得属性结点对应的定义信息
			local prop_build = Gtkui.GetWidgetProperty(prop_info, widget_data, nil, nil);
			-- 不为空
			if prop_build ~= nil then
				if prop_build.macro_code ~= nil then
					-- 插入到结果哈希中
					for name, code  in pairs(prop_build.macro_code) do
						-- 如果不存在，则创建一级空表
						if code_hash[name] == nil then
							code_hash[name] = {}
						end
						-- 插入到表中：二级索引
						code_hash[name][code] = true
					end
				end
			end
		end

		-- 递归处理子节点
        if widget_data.child ~= nil and widget_data.child.widget then
			-- 遍历所有child_property属性
			if widget_data.child.packing then
				for _, child_packing in ipairs(widget_data.child.packing) do
					-- 遍历所有packing属性
					for child_prop_name, _ in pairs(child_packing) do
						-- 查找对应子属性的定义信息
						local child_prop_info = Gtkui.GetPackingProperty(widget_data, child_prop_name)
						-- 如果不为空，且macro_code不为空，则生成代码
						if child_prop_info ~= nil and child_prop_info.macro_code ~= nil then
							for name, code  in pairs(child_prop_info.macro_code) do
								if code_hash[name] == nil then
									code_hash[name] = {}
								end
								code_hash[name][code] = true
							end
						end
					end
				end
			end

			for _, child_widget in ipairs(widget_data.child.widget) do
				recursion_get_macro_code(child_widget, code_hash)
			end
        end
    end

	local result_hash = {}
	local result_list = {}

    -- 递归处理
    recursion_get_macro_code(widget_data, result_hash)

	-- 如果指定ID下没有宏代码，则返回一个空列表
	if result_hash[type_id] == nil then
		return {}
	end

	-- 开始处理hash
	for name, _ in pairs(result_hash[type_id]) do
		table.insert(result_list, name)
	end

	-- 返回结果列表
	return result_list
end

-- 返回当前控件的属性所有前置声明
function Gtkui.GetMacroCodeDefines(name)
	if Gtkui.CodePatchList[name] ~= nil then
		return Gtkui.CodePatchList[name]
	end
	print("[GenMacroCodeDefine] Unknown macro code name: " .. name)
	return ""
end

-- 从XML文件中读取GTK版本号
function get_gtk_version_from_xml(ui_handle, default_version)
    local function get_version_property(ui_handle, child_node, name)
        -- 第一个属性
        local prop_item = get_gtk_ui_first_property(ui_handle, child_node)
        while prop_item ~= nil do
            local prop_name = get_gtk_ui_property_name(ui_handle, child_node, prop_item)
            if prop_name == name then
                return get_gtk_ui_property_value(ui_handle, child_node, prop_item)
            end
            prop_item = get_gtk_ui_next_property(ui_handle, child_node, prop_item)
        end
        return nil
    end
    -- 则根据XML文件中的类型，require libs version来确定gtk版本
    local root_note = get_gtk_ui_root(ui_handle);
    -- 如果是interface，
    if get_gtk_ui_node_name(ui_handle, root_note) == "interface" then
        -- 第一个子结点
        local child_node = get_gtk_ui_first_child(ui_handle, root_note)
        while child_node ~= nil do
            local node_name = get_gtk_ui_node_name(ui_handle, child_node)
            if node_name == "requires" then
                -- 第一个属性
                local prop_value = get_version_property(ui_handle, child_node, "version")
                -- 如果没有相应版本号内容，则返回默认版本号
                if prop_value == nil then
                    return default_version
                end
                local main_ver = string.byte(prop_value, 1)
                -- gtk2 => gtk 224
                if main_ver == 50 then -- "2"
                    return "224"
                -- gtk3 => gtk 324
                elseif main_ver == 51 then -- "3"
                    return "324"
                else -- "4"
                    return string.gsub(prop_value, "%.", "")
                end
            end
            child_node = get_gtk_ui_next_child(ui_handle, root_note, child_node)
        end
        -- gtk_version = "224"
    else
        print("[ERROR]unknown ui file!")
        return nil
    end
end

-- 总入口，生成GTK代码
function gen_gtk_code(ui_data, template_file, output_folder, project_id_file, main_widget, app_name)
	local function format_gtk_code(ui_data)
		-- 此函数用于format_widget_node的后处理
		local post_func = function(widget_data, class_name, id_value)
			-- 转换提取完成后，需要后处理一下，
			widget_data["property"]["id"] = widget_data["property"]["class"];
			widget_data["property"]["id"]["name"] = "id";
			widget_data["property"]["class"] = widget_data["property"]["parent"];
			widget_data["property"]["class"]["name"] = "class";
			widget_data["property"]["parent"] = nil;
		end
		-- 取得根结点 
		local root_node = get_gtk_ui_root(ui_data);
		-- 非空再生成
		if root_node ~= nil then
			-- 可以校验一下，是否为interface结点
	
			-- 取得第一个子结点
			local child_node = get_gtk_ui_first_child(ui_data, root_node);
	
			-- 保存格式化的控件数据
			local widget_list = {};
			-- 循环处理每一个子结点
			while child_node ~= nil do
				-- 取得结点名称
				local object_name = get_gtk_ui_node_name(ui_data, child_node);
				-- 校验
				if object_name ~= nil then
					-- Top控件
					if object_name == "object" then
						-- 获取控件ID
						local class_name, id_value = Gtkui.get_gtk_widget_class_and_id(ui_data, child_node, "id", "class");
						if id_value ~= nil then
							-- 调用接口格式化转换对象数据
							widget_list[id_value] = Gtkui.FormatWidgetNode(ui_data, child_node, {class_name, id_value});
						end
					elseif object_name == "template" then
						-- 模板的话，需要特殊处理
						local class_name, id_value = Gtkui.get_gtk_widget_class_and_id(ui_data, child_node, "class", "parent");
						-- 需要判空
						if id_value ~= nil then
							-- 调用接口格式化转换对象数据，还需要做一下后处理
							widget_list[id_value] = Gtkui.FormatWidgetNode(ui_data, child_node, {class_name, id_value}, post_func);
						end
					else
						print ("[WARN] Skip Top Widget : " .. object_name);
					end
				else
					print ("[WARN] Bad Top Widget, without name!");
				end
				-- 取得下一子结点
				child_node = get_gtk_ui_next_child(ui_data, root_node, child_node);
			end
			return widget_list;
		end
		return nil;
	end
	-- 生成控件依赖列表
	local function build_top_widget_depends_list(widget_list)
		local function get_widget_depends_list(widget)
			local dep_hash = {}
			local dep_list = {}
			-- 遍历所有属性
			for _, prop_info in pairs(widget.property) do
				-- 取得属性结点对应的原始信息
				local prop_define = Gtkui.GetWidgetProperty(prop_info, widget, nil, nil)
				
				if prop_define ~= nil then
					-- 外部依赖，取此属性的内容
					if prop_define.ext_depend ~= nil then
						-- 判断是否存在，不存在，则添加进去
						if dep_hash[prop_info.value] == nil then
							dep_hash[prop_info.value] = true
							table.insert(dep_list, prop_info.value)
						end
					elseif prop_define.tmpl_depend ~= nil then -- 模板依赖，取当前控件的ID值
						-- 判断是否存在，不存在，则添加进去
						if dep_hash[widget.property.id.value] == nil then
							dep_hash[widget.property.id.value] = true
							table.insert(dep_list, widget.property.id.value)
						end
						break; -- 模板依赖，只需要一个即可
					end
				end
			end
			-- child非空
			if widget.child ~= nil and widget.child.widget ~= nil then
				-- 递归处理每个子结点
				for _, child_widget in pairs(widget.child.widget) do
					-- 遍历子控件，并递归取得相应的依赖列表
					local child_list = get_widget_depends_list(child_widget)
					-- 不为空，则进行合并
					if #child_list > 0 then
						for _, child_name in ipairs(child_list) do
							-- 如果不存在，则添加进去
							if dep_hash[child_name] == nil then
								dep_hash[child_name] = true
								table.insert(dep_list, child_name)
							end
						end
					end
				end
			end
			return dep_list
		end	
		-- 遍历所有顶层控件
		for idx_1, widget in pairs(widget_list) do
			Gtkui.widget_depends_list[widget.property.id.value] = get_widget_depends_list(widget)
		end
		-- 同时，将所有模板控件也添加进去，模板控件，则不会在根列表中显示
		if Gtkui.ProjectIdList == nil then
			return
		end
		for _, id_list in pairs(Gtkui.ProjectIdList) do
			-- 只拷贝相应的模板控件，普通控件不拷贝过来
			if id_list.is_template and id_list.class ~= nil then
				-- 添加到依赖列表中，模板控件的实际依赖值，并不修改
				if Gtkui.widget_depends_list[id_list.class] == nil then
					Gtkui.widget_depends_list[id_list.class] = {}
				end
			end
		end
	end
	-- 生成控件的外部模块列表
	local function build_top_widget_ext_mod_list(widget_list)
		local function get_widget_ext_mod_list(widget)
			local ext_mod_hash = {};
			local ext_mod_list = {};

			-- 检查组件所属的类
			local widget_class = Gtkui.GetWidgetClass(widget);
			-- 判断对应变量是否存在
			if widget_class ~= nil then
				if widget_class.ext_modules ~= nil then
					for _, child_name in ipairs(widget_class.ext_modules) do
						-- 如果不存在，则添加进去
						if ext_mod_hash[child_name] == nil then
							ext_mod_hash[child_name] = true
							table.insert(ext_mod_list, child_name)
						end
					end
				end
			end
			
			-- child非空
			if widget.child ~= nil and widget.child.widget ~= nil then
				-- 递归处理每个子结点
				for _, child_widget in pairs(widget.child.widget) do
					-- 遍历子控件，并递归取得相应的依赖列表
					local child_list = get_widget_ext_mod_list(child_widget)
					-- 不为空，则进行合并
					if #child_list > 0 then
						for _, child_name in ipairs(child_list) do
							-- 如果不存在，则添加进去
							if ext_mod_hash[child_name] == nil then
								ext_mod_hash[child_name] = true
								table.insert(ext_mod_list, child_name)
							end
						end
					end
				end
			end
			return ext_mod_list
		end
		-- 遍历所有顶层控件
		for _, widget in pairs(widget_list) do
			-- 保存其相应的外部模块依赖列表
			Gtkui.ext_module_list[widget.property.id.value] = get_widget_ext_mod_list(widget)
		end
	end
	-- 生成控件的外部头文件列表
	local function build_top_widget_ext_inc_file_list(widget_list)
		local function get_widget_ext_inc_file_list(widget)
			local ext_inc_hash = {};
			local ext_inc_list = {};

			-- 检查组件所属的类
			local widget_class = Gtkui.GetWidgetClass(widget);
			-- 判断对应变量是否存在
			if widget_class ~= nil then
				if widget_class.ext_inc_files ~= nil then
					for _, child_name in ipairs(widget_class.ext_inc_files) do
						-- 如果不存在，则添加进去
						if ext_inc_hash[child_name] == nil then
							ext_inc_hash[child_name] = true
							table.insert(ext_inc_list, child_name)
						end
					end
				end
			end
			
			-- child非空
			if widget.child ~= nil and widget.child.widget ~= nil then
				-- 递归处理每个子结点
				for _, child_widget in pairs(widget.child.widget) do
					-- 遍历子控件，并递归取得相应的依赖列表
					local child_list = get_widget_ext_inc_file_list(child_widget)
					-- 不为空，则进行合并
					if #child_list > 0 then
						for _, child_name in ipairs(child_list) do
							-- 如果不存在，则添加进去
							if ext_inc_hash[child_name] == nil then
								ext_inc_hash[child_name] = true
								table.insert(ext_inc_list, child_name)
							end
						end
					end
				end
			end
			return ext_inc_list
		end
		-- 遍历所有顶层控件
		for _, widget in pairs(widget_list) do
			-- 保存其相应的外部头文件列表
			Gtkui.ext_inc_file_list[widget.property.id.value] = get_widget_ext_inc_file_list(widget)
		end
	end
	-- 处理模板文件，生成GTK代码
	local function process_tmpl_file(widget_list, template_file)
		-- 加载模板文件
		local tmpl_code = Gtkui.require_template_code(template_file)
		if tmpl_code == nil then
			print("[ERROR] load template file fail: " .. template_file)
			return
		end

		-- 先调用预处理函数
		if tmpl_code[1] ~= nil and type(tmpl_code[1]) == "function" then
			local ret = tmpl_code[1](widget_list)
			if ret == nil or (not ret) then
				print("[ERROR] prev doing file fail: " .. template_file)
			end
		else
			print("[WARN] missing prev doing function in template file: " .. template_file)
		end

		-- 生成代码
		if tmpl_code[2] ~= nil and type(tmpl_code[2]) == "function" then
			local ret = tmpl_code[2](widget_list)
			if ret == nil or (not ret) then
				print("[ERROR] gencode file fail: " .. template_file)
			end
		else
			print("[ERROR] missing gencode function in template file: " .. template_file)
		end

		-- 后处理代码
		if tmpl_code[3] ~= nil and type(tmpl_code[3]) == "function" then
			local ret = tmpl_code[3](widget_list)
			if ret == nil or (not ret) then
				print("[ERROR] prev doing file fail: " .. template_file)
			end
		else
			print("[WARN] missing post doing function in template file: " .. template_file)
		end
	end
	local function patch_widget_to_tmpl_class(widget)
		for _, tmpl_info in ipairs(Gtkui.ProjectIdList) do
			if tmpl_info.is_template then
				-- id == class, class == parent，则完全匹配
				if widget.property.id.value == tmpl_info.class then
					if widget.property.class.value == tmpl_info.parent then
						-- print("[INFO] widget tmpl match, id: " .. widget.property.id.value .. ", class: " .. widget.property.class.value .. ", tmpl parent: " .. tmpl_info.parent)
						-- 修改这个类的类名，同时添加一个__parent_class__属性，用于记录模板信息
						widget.property.class.value  = "GtkTmplWidget" .. tmpl_info.parent
						widget.property.__parent_class__ = { name = "__parent_class__", value = tmpl_info.parent};
					else
						print("[ERROR] widget class mismatch to tmpl parent, id: " .. widget.property.id.value .. ", class: " .. widget.property.class.value .. ", tmpl parent: " .. tmpl_info.parent)
					end
					-- ID要求是全局唯一，因此此时可以返回了
					return
				end
			end
		end
	end
-- 根据项目ID列表，判断某些控件是否为外部模板控件
	local function patch_template_widget(widget_list, is_top)		
		-- 如果不需要调整，则直接返回
		if Gtkui.ProjectIdList == nil then
			return
		end
		-- 遍历所有控件
		for idx_1, widget in pairs(widget_list) do
			-- 当前控件为模板控件，且不为顶层控件，则进行补丁操作，否则会被跳过
			if not is_top then
				patch_widget_to_tmpl_class(widget)
			end
			
			-- child非空
			if widget.child ~= nil and widget.child.widget ~= nil then
				-- 递归处理每个子结点
				patch_template_widget(widget.child.widget, false)
			end
		end
	end
	-- 根据组件的属性类型，将属性值转换为C语言的格式
	local function patch_property_value_to_c_format(property_, widget_)
		-- 判断对应属性在当前类中是否存在
		local property_build = Gtkui.GetWidgetProperty(property_, widget_, nil, nil);
		-- 如果某个属性没有
		if property_build["__type__"] == nil then
			print("[ERROR] missing type in property, widget: [" .. widget_.property.class.value .. "] in patch property name: " .. property_.name)
			return;
		end
		-- local prop_type = property_build["__type__"];
		-- 调用接口对进打补丁
		Gtkui.PatchOneProperyValueToCFormat(property_, property_build, widget_.property.class.value)
	end
	-- 根据组件的packing类型，将属性值转换为C语言的格式
	local function patch_widget_packings_to_c_format(packing_, widget_)
		-- 判断对应属性在当前类中是否存在
		local packing_build = Gtkui.GetPackingProperty(widget_, packing_.name)
		-- 判断对应变量是否存在
		if packing_build == nil then
			print("[ERROR] missing type data, widget name : " .. widget_.property.class.value .. " in patch packing name: " .. packing_.name)
			return;
		end
		-- 调用接口对进打补丁
		Gtkui.PatchOneProperyValueToCFormat(packing_, packing_build, widget_.property.class.value)
	end
	local function patch_widget_properties_to_c_format(widget_list, packing_list, parent)
		-- 遍历所有控件
		for idx_1, widget in pairs(widget_list) do
			-- property非空
			if widget.property ~= nil then
				-- 遍历所有属性
				for _2, property in pairs(widget.property) do
					-- 如果属性值存在
					if property.value ~= nil then
						patch_property_value_to_c_format(property, widget)
					end
				end
			end
			-- child非空
			if widget.child ~= nil and widget.child.widget ~= nil then
				-- 递归处理每个子结点
				patch_widget_properties_to_c_format(widget.child.widget, widget.child.packing, widget)
			end
			-- 处理packing属性
			if packing_list ~= nil and packing_list[idx_1] ~= nil then
				for _4, packing_ in pairs(packing_list[idx_1]) do
					-- 如果属性值存在
					if packing_.value ~= nil then
						-- 遍历处理每个packing下的属性
						patch_widget_packings_to_c_format(packing_, parent)
					end
				end
			end
		end
	end
	
	-- 拆分出模板文件名与路径
	--local pathinfo = {string.match(template_file, "(.-)(([^\\/]-)%.?([^%.\\/]*))$")}
	local pathinfo = GtkUtils.split_pathinfo(template_file)

	-- 将模板文件路径添加到搜索路径中
	package.path = package.path .. ";" .. pathinfo[1] .. "/?.tmpl"
	-- 同时设置模板文件夹
	Gtkui.set_template_folder(pathinfo[1])
	-- 设置输出文件夹
	Gtkui.set_output_folder(output_folder)

	-- 判断project_id_file是否存在
	if project_id_file ~= nil then
		-- 加载项目ID文件
		dofile(project_id_file)
	end

	-- 将ui_data格式化一下
    local widget_list = format_gtk_code(ui_data);

	-- 需要先根据项目ID列表，判断某些控件是否为外部模板控件，并且修改好相应的类名
	patch_template_widget(widget_list, true);

	-- 生成控件依赖列表
	build_top_widget_depends_list(widget_list);

	-- 生成顶层控件的外部模块列表
	build_top_widget_ext_mod_list(widget_list);

	-- 生成控件的外部头文件列表
	build_top_widget_ext_inc_file_list(widget_list);

	-- 如果主控件名不为空
	if main_widget ~= nil and type(main_widget) =="string" then
		Gtkui.set_main_widget(main_widget)
	else
		print("[ERROR] miss or bad main widget name, use first GtkWidget name")
		-- 查找到第一个就设置下去
		local first_widget = Gtkui.find_first_gtk_widget(widget_list, "GtkWidget")
		if first_widget ~= nil then
			Gtkui.set_main_widget(first_widget)
		else
			print("[ERROR] find first GtkWidget fail, use first widget name.")
			for key, _ in pairs(widget_list) do
				Gtkui.set_main_widget(key)
				break;
			end
		end
	end
	-- 如果主应用名称不为空
	if app_name ~= nil and type(app_name) =="string" then
		Gtkui.set_main_appname(app_name)
	end

	-- 判断当前控件列表中是否有主控件，有则设置主控件标志为true，否则为false
	Gtkui.has_main_widget = false
	for _, widget in pairs(widget_list) do
		if widget.property.id.value == Gtkui.get_main_widget() then
			Gtkui.has_main_widget = true
			break;
		end
	end

	-- 对所有的属性数据进行Patch，保证格式符合C语言的语法要求
	patch_widget_properties_to_c_format(widget_list, nil, nil);

	-- 开始处理模板文件
	process_tmpl_file(widget_list, pathinfo[3]);
end

-- 判断当前UI文件是否有主控件，暂时不需要参数
function Gtkui.HasMainWidget() -- main_widget_name, root)
	if Gtkui.has_main_widget == true then
		return true
	end
	return false
end

-- 自动合并文件
function auto_merge_file(file_name, file_content, tags)
	-- 读取文件内容
	local function read_file(path)
		local file = io.open(path, "rb")
		if not file then return nil end
		local content = {}
		for line in file:lines() do
			table.insert(content, line)
		end
		file:close()
		return content
	end
	-- 以行为单位写入文件
	local function write_file_with_lines(path, content)
		local file = io.open(path, "wb")
		if not file then return nil end
		for i, line in ipairs(content) do
			file:write(line.."\n")
		end
		file:close()
		return true
	end
	-- 根据标签，分析内容，
	local function analyze_content(content, tags)
		-- 结果
		local result = {
			-- 文件内容，以行为单位，每行一个字符串，数组形式组织
			content = content,
			-- 标签列表，数组形式组织，每个元素是一个table，table中包含三个属性，一个是标签名（字符串），一个是标签起始行号，一个是标签结束行号
			tag_list = {
			},
			-- 标签索引，字典形式组织，key是标签名，value是tag_list中的数组索引
			tag_index = {
			}
		};
		-- 开始标签
		local start_tag = tags[1]
		-- 结束标签
		local end_tag = tags[2]
		-- 标签的模式匹配组
		local tag_pattern = start_tag .. "(.-)" .. end_tag

		-- 遍历内容
		local list_idx = 1
		local line_idx = 1
		for _, line in ipairs(content) do
			-- 删除一些空白字符，再判断是否为标签行
			local real_line = GtkUtils.trim2(line)
			-- 找到标签
			if string.find(real_line, start_tag) ~= nil and
			string.find(real_line, end_tag) ~= nil then
				local tag_name = string.match(real_line, tag_pattern)
				-- 如果已经有这个名字了
				if result.tag_index[tag_name] ~= nil then
					-- 取得索引
					local tag_index = result.tag_index[tag_name]
					-- 找到标签，则更新索引
					result.tag_list[tag_index].end_line = line_idx
				else
					-- 未找到标签，则添加到列表中
					table.insert(result.tag_list, {tag_name = tag_name, start_line = line_idx, end_line = line_idx} )
					-- 添加到索引中
					result.tag_index[tag_name] = list_idx
					-- 索引加1
					list_idx = list_idx + 1;
				end
			end
			line_idx = line_idx + 1
		end
		return result
	end
	-- 自动合并结果，并返回内容
	local function auto_merge_result(old_result, new_result)
		-- 创建一个新结果
		local last_result = {}
		-- 首先，分析旧结果，
		if old_result.tag_list[1] == nil then
			-- 如果旧结果没有标签，
			last_result = old_result.content
			-- 将新结果中，所有标签内的内容，全部添加到新结果中
			for _, new_tag in ipairs(new_result.tag_list) do
				-- 取得开始行，结束行
				local start_line = new_tag.start_line
				local end_line = new_tag.end_line
				-- 将内容插入结果中
				for i = start_line, end_line do
					table.insert(last_result, new_result.content[i])
				end
			end
		else
			-- 首先，取得第一个标签
			local first_tag = old_result.tag_list[1]
			-- 将第一个标签前的内容插入结果中
			if first_tag.start_line > 1 then
				for i = 1, first_tag.start_line - 1 do
					table.insert(last_result, old_result.content[i])
				end
			end

			-- 依次处理旧结果中的标签
			for old_tag_idx, old_tag in ipairs(old_result.tag_list) do
				local tag_name = old_tag.tag_name

				local new_tag_idx = new_result.tag_index[tag_name]
				-- 如果标签在新结果中存在，则处理（不存在，则应该删除之）
				if new_tag_idx ~= nil then
					-- 如果标签在新结果中存在，则应该将新结果中的内容，插入到旧结果中
					local new_tag = new_result.tag_list[new_tag_idx]
					-- 取得开始行，结束行
					local start_line = new_tag.start_line
					local end_line = new_tag.end_line
					-- 先将内容插入结果中
					for i = start_line, end_line do
						table.insert(last_result, new_result.content[i])
					end

					-- 此时，需要判断新结果中，下一标签的位置，是否在旧结果中
					local next_new_tag_idx = new_tag_idx + 1
					-- 判断是否结束
					while next_new_tag_idx < #new_result.tag_list do
						-- 取得下一个标签
						local next_new_tag = new_result.tag_list[next_new_tag_idx]
						-- 在旧结果中，直接退出
						if old_result.tag_index[next_new_tag.tag_name] ~= nil then
							-- 在其中，可以直接跳出了
							break;
						end
						-- 取得开始行，结束行
						local start_line = next_new_tag.start_line
						local end_line = next_new_tag.end_line
						-- 先将内容插入结果中
						for i = start_line, end_line do
							table.insert(last_result, new_result.content[i])
						end

						next_new_tag_idx = next_new_tag_idx + 1
					end
				else
					-- 如果标签在新结果中不存在，则应该删除之
					-- 在这里，如果添加一些代码，可以删除标签间用户自定义的一些代码，比如signal的处理函数代码
					-- 比如，根据[]标志来区分需要删除的代码，如果标签中带[]标志，且有关联，在新结果中不存在，则删除之？
				end

				-- 如果不是最后一个标签，则先将标签后的旧内容插入结果中
				local tail_start_line = old_tag.end_line + 1
				local tail_end_line = tail_start_line
				if old_tag_idx < #old_result.tag_list then
					-- 取得下一个旧标签信息
					local next_tag = old_result.tag_list[old_tag_idx + 1]
					-- tail_end_line等于下一个旧标签的开始行
					tail_end_line = next_tag.start_line - 1
				else
					-- 如果是最后一个标签，则tail_end_line等于文件内容行数
					tail_end_line = #old_result.content
				end
				-- 如果标签后有内容，则添加进去
				if tail_start_line <= tail_end_line then
					for i = tail_start_line, tail_end_line do
						table.insert(last_result, old_result.content[i])
					end
				end
			end
		end
		return last_result;
	end
	-- 将文件内容拆分成行
	local function content_to_lines(file_content)
		local result = {}
		for line, _ in file_content:gmatch'([^\r\n]*)[\r\n]' do
			table.insert(result, line)
		end
		return result
	end

	-- 读取文件内容
	local old_content = read_file(file_name)

	-- 根据标签，分析内容，
	local old_result = analyze_content(old_content, tags)

	-- 将文件内容拆分成行
	local tmp_content = content_to_lines(file_content)

	-- 根据标签，分析内容，
	local new_result = analyze_content(tmp_content, tags)

	-- 合并新变更的内容到之前的结果中
	local new_content = auto_merge_result(old_result, new_result)

	-- 写入文件
	write_file_with_lines(file_name, new_content)
end